{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Breaking Hardware AES on CW305 FPGA (and other FPGA targets)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This tutorial relies on previous knowledge from the SCA101 course notebooks (in `../courses/sca101/`); make sure you go through these first to understand how a CPA attack works.\n",
    "\n",
    "In this notebook, we'll apply knowledge from sca101 to break a hardware AES implementation on the CW305 Artix FPGA.\n",
    "\n",
    "Some out-of-date background on the target FPGA project is can be found here: [Tutorial CW305-1 Building a Project](http://wiki.newae.com/Tutorial_CW305-1_Building_a_Project) (ignore the \"capture setup\" section, which uses the obsolete ChipWhisperer GUI; this notebook shows all you need to know about capture setup on the CW305 with Jupyter).\n",
    "\n",
    "While this notebook has \"CW305\" in its title, it can also be used with the CW312T-A35 and CW312T-iCE40 targets."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Background Theory\n",
    "During this tutorial, we'll be working with a hardware AES implementation. This type of attack can be much more difficult than a software AES attack. In the software AES attacks, we needed hundreds or thousands of clock cycles to capture the algorithm's full execution. In contrast, a hardware AES implementation may have a variety of speeds. Depending on the performance of the hardware, a whole spectrum of execution speeds can be achieved by executing many operations in a single clock cycle. It is theoretically possible to execute the entire AES encryption in a single cycle, given enough hardware space and provided that the clock is not too fast. Most hardware accelerators are designed to complete one round or one large part of a round in a single cycle.\n",
    "\n",
    "This fast execution may cause problems with a regular CPA attack. In software, we found that it was easy to search for the outputs of the s-boxes because these values would need to be loaded from memory onto a high-capacitance data bus. This is not necessarily true on an FPGA, where the output of the s-boxes may be directly fed into the next stage of the algorithm. In general, we may need some more knowledge of the hardware implementation to successfully complete an attack.\n",
    "\n",
    "In our case, let's suppose that every round of AES is completed in a single clock cycle. Recall the execution of AES:\n",
    "\n",
    "<img src=\"img/aes_operations.png\" width=\"250\">\n",
    "\n",
    "Here, every blue block is executed in one clock cycle. This means that an excellent candidate for a CPA attack is the difference between the input and output of the final round. It is likely that this state is stored in a port that is updated every round, so we expect that the Hamming distance between the round input and output is the most important factor on the power consumption. Also, the last round is the easiest to attack because it has no MixColumns operation. We'll use this Hamming distance as the target in our CPA attack."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Capture Notes\n",
    "\n",
    "Most of the capture settings used below are similar to the standard ChipWhisperer scope settings. However, there are a couple of interesting points:\n",
    "\n",
    "- We're only capturing 129 samples (the minimum allowed with CW-lite), and the encryption is completed in less than 60 samples with an x4 ADC clock. This makes sense - as we mentioned above, our AES implementation is computing each round in a single clock cycle.\n",
    "- We're using EXTCLK x4 for our ADC clock. This means that the FPGA is outputting a clock signal, and we aren't driving it.\n",
    "\n",
    "Other than these, the last interesting setting is the number of traces. By default, the capture software is ready to capture 5000 traces - many more than were required for software AES! It is difficult for us to measure the small power spikes from the Hamming distance on the last round: these signals are dwarfed by noise and the other operations on the chip. To deal with this small signal level, we need to capture many more traces."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Capture Setup"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Setup is somewhat similar to other targets, except that we are using an external clock (driven from the FPGA-- unless you're using the CW312T-A35 target). We'll also do the rest of the setup manually:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer as cw\n",
    "scope = cw.scope()\n",
    "scope.default_setup()\n",
    "if scope._is_husky:\n",
    "    scope.adc.samples = 80\n",
    "else:\n",
    "    scope.adc.samples = 129\n",
    "scope.adc.offset = 0\n",
    "scope.adc.basic_mode = \"rising_edge\"\n",
    "scope.trigger.triggers = \"tio4\"\n",
    "scope.io.tio1 = \"serial_rx\"\n",
    "scope.io.tio2 = \"serial_tx\"\n",
    "scope.io.hs2 = \"disabled\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we connect to the target board and program it with the correct bitfile.\n",
    "\n",
    "If you have a CW305, you must correctly specify the variant (either 'CW305_35t' or 'CW305_100t')."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#TARGET_PLATFORM = 'CW305_100t'\n",
    "#TARGET_PLATFORM = 'CW305_35t'\n",
    "TARGET_PLATFORM = 'CW312T_A35'\n",
    "#TARGET_PLATFORM = 'CW312T_ICE40'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if TARGET_PLATFORM in ['CW312T_A35', 'CW312T_ICE40']:\n",
    "    scope.io.hs2 = 'clkgen'\n",
    "    fpga_id = None # not needed\n",
    "    if TARGET_PLATFORM == 'CW312T_A35':\n",
    "        platform = 'ss2_a35'\n",
    "        scope.gain.db = 45 # this is a good setting for the inductive shunt; if using another, adjust as needed\n",
    "    else:\n",
    "        platform = 'ss2_ice40'\n",
    "        scope.gain.db = 15\n",
    "else:\n",
    "    scope.gain.db = 25\n",
    "    scope.io.hs2 = \"disabled\"\n",
    "    platform = 'cw305'\n",
    "    if TARGET_PLATFORM == 'CW305_100t':\n",
    "        fpga_id = '100t'\n",
    "    elif TARGET_PLATFORM == 'CW305_35t':\n",
    "        fpga_id = '35t'\n",
    "\n",
    "# On the CW305, setting force=False only programs the FPGA if it is currently unprogrammed, whereas force=True programs the FPGA regardless.\n",
    "# This option isn't available on the CW312T_A35 or CW312T_ICE40.\n",
    "target = cw.target(scope, cw.targets.CW305, force=True, fpga_id=fpga_id, platform=platform)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next we set all the PLLs. We enable CW305's PLL1; this clock will feed both the target and the CW ADC. As explained [here](http://wiki.newae.com/Tutorial_CW305-1_Building_a_Project#Capture_Setup), **make sure the DIP switches on the CW305 board are set as follows**:\n",
    "- J16 = 0\n",
    "- K16 = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if TARGET_PLATFORM in ['CW305_100t', 'CW305_35t']:\n",
    "    target.vccint_set(1.0)\n",
    "    # we only need PLL1:\n",
    "    target.pll.pll_enable_set(True)\n",
    "    target.pll.pll_outenable_set(False, 0)\n",
    "    target.pll.pll_outenable_set(True, 1)\n",
    "    target.pll.pll_outenable_set(False, 2)\n",
    "\n",
    "    # run at 10 MHz:\n",
    "    target.pll.pll_outfreq_set(10E6, 1)\n",
    "\n",
    "    # 1ms is plenty of idling time\n",
    "    target.clkusbautooff = True\n",
    "    target.clksleeptime = 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "CW-Husky requires a different setup when the ADC clock is driven by the target:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if TARGET_PLATFORM in ['CW305_100t', 'CW305_35t']:\n",
    "    if scope._is_husky:\n",
    "        scope.clock.clkgen_freq = 10e6\n",
    "        scope.clock.clkgen_src = 'extclk'\n",
    "        scope.clock.adc_mul = 4\n",
    "        # if the target PLL frequency is changed, the above must also be changed accordingly\n",
    "    else:\n",
    "        scope.clock.adc_src = \"extclk_x4\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If using the CW312T-A35 target, the capture hardware needs to drive the target clock:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if TARGET_PLATFORM in ['CW312T_A35', 'CW312T_ICE40']:\n",
    "    scope.clock.clkgen_freq = 7.37e6\n",
    "    scope.io.hs2 = 'clkgen'\n",
    "    if scope._is_husky:\n",
    "        scope.clock.clkgen_src = 'system'\n",
    "        scope.clock.adc_mul = 4\n",
    "        scope.clock.reset_dcms()\n",
    "    else:\n",
    "        scope.clock.adc_src = \"clkgen_x4\"\n",
    "    import time\n",
    "    time.sleep(0.1)\n",
    "    target._ss2_test_echo()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, ensure the ADC clock is locked:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "for i in range(5):\n",
    "    scope.clock.reset_adc()\n",
    "    time.sleep(1)\n",
    "    if scope.clock.adc_locked:\n",
    "        break \n",
    "assert (scope.clock.adc_locked), \"ADC failed to lock\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Occasionally the ADC will fail to lock on the first try; when that happens, the above assertion will fail (and on the CW-Lite, the red LED will be on). Simply re-running the above cell again should fix things."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Trace Capture\n",
    "Below is the capture loop. The main body of the loop loads some new plaintext, arms the scope, sends the key and plaintext, then finally records and appends our new trace to the `traces[]` list.\n",
    "\n",
    "Because we're capturing 5000 traces, this takes a bit longer than the attacks against software AES implementations.\n",
    "\n",
    "Note that the encryption result is read from the target and compared to the expected results, as a sanity check."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "project_file = \"projects/Tutorial_HW_CW305.cwp\"\n",
    "project = cw.create_project(project_file, overwrite=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tqdm.notebook import tnrange\n",
    "import numpy as np\n",
    "import time\n",
    "from Crypto.Cipher import AES\n",
    "\n",
    "ktp = cw.ktp.Basic()\n",
    "\n",
    "traces = []\n",
    "textin = []\n",
    "keys = []\n",
    "N = 5000  # Number of traces\n",
    "\n",
    "# initialize cipher to verify DUT result:\n",
    "key, text = ktp.next()\n",
    "cipher = AES.new(bytes(key), AES.MODE_ECB)\n",
    "\n",
    "for i in tnrange(N, desc='Capturing traces'):\n",
    "    # run aux stuff that should come before trace here\n",
    "\n",
    "    key, text = ktp.next()  # manual creation of a key, text pair can be substituted here\n",
    "    textin.append(text)\n",
    "    keys.append(key)\n",
    "    \n",
    "    ret = cw.capture_trace(scope, target, text, key)\n",
    "    if not ret:\n",
    "        print(\"Failed capture\")\n",
    "        continue\n",
    "\n",
    "    assert (list(ret.textout) == list(cipher.encrypt(bytes(text)))), \"Incorrect encryption result!\\nGot {}\\nExp {}\\n\".format(ret.textout, list(text))\n",
    "    #trace += scope.getLastTrace()\n",
    "        \n",
    "    traces.append(ret.wave)\n",
    "    project.traces.append(ret)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This shows how a captured trace can be plotted:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from bokeh.plotting import figure, show\n",
    "from bokeh.io import output_notebook\n",
    "\n",
    "output_notebook()\n",
    "p = figure(width=800)\n",
    "\n",
    "xrange = list(range(len(traces[0])))\n",
    "p.line(xrange, traces[0], line_color=\"red\")\n",
    "show(p)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally we save our traces and disconnect. By saving the traces, the attack can be repeated in the future without having to repeat the trace acquisition steps above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "project.save()\n",
    "scope.dis()\n",
    "target.dis()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Attack\n",
    "Now we re-open our saved project and specify the attack parameters. For this hardware AES implementation, we use a different leakage model and attack than what is used for the software AES implementations.\n",
    "\n",
    "Note that this attack requires only the ciphertext, not the plaintext."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer as cw\n",
    "import chipwhisperer.analyzer as cwa\n",
    "project_file = \"projects/Tutorial_HW_CW305\"\n",
    "project = cw.open_project(project_file)\n",
    "attack = cwa.cpa(project, cwa.leakage_models.last_round_state_diff)\n",
    "cb = cwa.get_jupyter_callback(attack)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This runs the attack:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "attack_results = attack.run(cb)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The attack results can be saved for later viewing or processing without having to repeat the attack:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pickle\n",
    "pickle_file = project_file + \".results.pickle\"\n",
    "pickle.dump(attack_results, open(pickle_file, \"wb\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You may notice that we didn't get the expected key from this attack, but still got a good difference in correlation between the best guess and the next best guess. This is because we actually recovered the key from the last round of AES. We'll need to use analyzer to get the actual AES key: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from chipwhisperer.analyzer.attacks.models.aes.key_schedule import key_schedule_rounds\n",
    "recv_lastroundkey = [kguess[0][0] for kguess in attack_results.find_maximums()]\n",
    "recv_key = key_schedule_rounds(recv_lastroundkey, 10, 0)\n",
    "for subkey in recv_key:\n",
    "    print(hex(subkey))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tests\n",
    "Check that the key obtained by the attack is the key that was used.\n",
    "This attack targets the last round key, so we have to roll it back to compare against the key we provided."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "key = list(key)\n",
    "assert (key == recv_key), \"Failed to recover encryption key\\nGot:      {}\\nExpected: {}\".format(recv_key, key)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Next steps\n",
    "\n",
    "The `jupyter/demos/CW305_ECC/` folder contains a series of tutorials for attacking hardware ECC on the CW305.\n",
    "\n",
    "This CW305 appnote contains additional details on the CW305 platform: http://media.newae.com/appnotes/NAE0010_Whitepaper_CW305_AES_SCA_Attack.pdf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
